#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
PLC数据模型定义
包含数据类型枚举和数据块变量类定义
"""

from enum import Enum
from dataclasses import dataclass


class PLCDataType(Enum):
    """PLC数据类型枚举"""
    # 基本数据类型
    BOOL = "BOOL"      # 布尔型，1位
    BYTE = "BYTE"      # 字节型，8位无符号
    WORD = "WORD"      # 字型，16位无符号
    DWORD = "DWORD"    # 双字型，32位无符号
    LWORD = "LWORD"    # 长字型，64位无符号
    
    # 有符号整数类型
    SINT = "SINT"      # 短整型，8位有符号 (-128 to 127)
    INT = "INT"        # 整型，16位有符号 (-32768 to 32767)
    DINT = "DINT"      # 双整型，32位有符号
    LINT = "LINT"      # 长整型，64位有符号
    
    # 无符号整数类型
    USINT = "USINT"    # 无符号短整型，8位 (0 to 255)
    UINT = "UINT"      # 无符号整型，16位 (0 to 65535)
    UDINT = "UDINT"    # 无符号双整型，32位
    ULINT = "ULINT"    # 无符号长整型，64位
    
    # 浮点数类型
    REAL = "REAL"      # 实数型，32位浮点 (IEEE 754)
    LREAL = "LREAL"    # 长实数型，64位浮点 (IEEE 754)
    
    # 字符串类型
    STRING = "STRING"  # 字符串型，可变长度 (ASCII)
    WSTRING = "WSTRING" # 宽字符串型，Unicode字符串
    CHAR = "CHAR"      # 字符型，单个ASCII字符
    WCHAR = "WCHAR"    # 宽字符型，单个Unicode字符
    
    # 时间类型
    TIME = "TIME"      # 时间型，持续时间
    LTIME = "LTIME"    # 长时间型，长持续时间
    DATE = "DATE"      # 日期型
    TIME_OF_DAY = "TIME_OF_DAY"  # 时刻型
    TOD = "TOD"        # 时刻型（简写）
    DATE_AND_TIME = "DATE_AND_TIME"  # 日期时间型
    DT = "DT"          # 日期时间型（简写）
    
    # S7特有类型
    S5TIME = "S5TIME"  # S5时间格式
    COUNTER = "COUNTER"  # 计数器
    TIMER = "TIMER"    # 定时器


@dataclass
class DataBlockVariable:
    """数据块变量定义类"""
    name: str                    # 变量名称
    db_number: int              # 数据块编号（DB号）
    start_offset: int           # 起始偏移地址（字节）
    bit_offset: int = 0         # 位偏移（仅BOOL类型使用）
    data_type: PLCDataType = PLCDataType.INT  # 数据类型
    unit: str = ""              # 单位
    description: str = ""       # 描述
    
    def get_address_string(self) -> str:
        """获取地址字符串表示"""
        if self.data_type == PLCDataType.BOOL:
            return f"DB{self.db_number}.DBX{self.start_offset}.{self.bit_offset}"
        elif self.data_type in [PLCDataType.BYTE, PLCDataType.SINT, PLCDataType.USINT, PLCDataType.CHAR]:
            return f"DB{self.db_number}.DBB{self.start_offset}"
        elif self.data_type in [PLCDataType.WORD, PLCDataType.INT, PLCDataType.UINT, PLCDataType.WCHAR]:
            return f"DB{self.db_number}.DBW{self.start_offset}"
        elif self.data_type in [PLCDataType.DWORD, PLCDataType.DINT, PLCDataType.UDINT, PLCDataType.REAL, 
                               PLCDataType.TIME, PLCDataType.DATE, PLCDataType.TIME_OF_DAY, PLCDataType.TOD,
                               PLCDataType.S5TIME, PLCDataType.COUNTER, PLCDataType.TIMER]:
            return f"DB{self.db_number}.DBD{self.start_offset}"
        elif self.data_type in [PLCDataType.LWORD, PLCDataType.LINT, PLCDataType.ULINT, PLCDataType.LREAL,
                               PLCDataType.LTIME, PLCDataType.DATE_AND_TIME, PLCDataType.DT]:
            return f"DB{self.db_number}.DBQ{self.start_offset}"  # 64位数据使用DBQ
        elif self.data_type in [PLCDataType.STRING, PLCDataType.WSTRING]:
            return f"DB{self.db_number}.DBB{self.start_offset}"
        else:
            return f"DB{self.db_number}.DB{self.start_offset}"
        
        

